#include "..\\include\Lib_Clara.h"
#include "..\\include\Dir.h"
#include "..\\include\cfg_items.h"
#include "..\\include\Types.h"
#include "conf_loader.h"
#include "config_data.h"
#include <math.h>

#define ELF_BCFG_CONFIG_EVENT 994
#define empty 0xFFFF
int Height,Width;
u16 ftimer;
PROCESS  pid;
float cnt;
float count=0;
unsigned int cpu=0,tim;
int imgh,  imgw;

DISP_OBJ_ONREDRAW_METHOD Display_oldReDraw = 0;
DISP_OBJ * GUI_display = 0;
DISP_DESC * Display_desc = 0;

void Display_ReDraw(DISP_OBJ * DO,int a, int b,int c);

typedef struct
{
	BOOK* book;
	wchar_t *bcfg_p;
	wchar_t *bcfg_n;
}MSG_BCFG;

typedef struct
{
	wchar_t ImageID;
	u16 ImageHandle;
}IMG;

const double PI = 3.14159265;

u16 timer;
GC *context=0;
IMG image;
IMG image1;
IMG image2;

typedef struct
{
	BOOK * book;
}MSG;

//Own idea for including font into app
//Created by mc_kibel
//Font will be drawn on 3x5 table
//1 - visible pixel, 0 - not visible pixel
//Now I'm sure you can see a symbols by looking only on 1's only :D

#define Pixel_Visible(_param_) _param_==1
#define NUMBERS_START 2
#define SYMBOL_START 0
#define CHARACTERS_START 12
#define _PLUS 0
#define _MINUS 1
#define NUMBER(_param_) NUMBERS_START+_param_
#define SYMBOL(_param_) SYMBOL_START+_param_

int CHAR (char param)
{
	int res = param;
	// if (res > 0x30 && res < 0x39) res += 1;
	//if (res > 0x60) res-=0x61;
	//res += NUMBERS_START;
	return (res-0x30);
}

int font_table[][3*5]={
                              { //0
                                      1,1,1,
                                      1,0,1,
                                      1,0,1,
                                      1,0,1,
                                      1,1,1
                              },
                              { //1
                                      0,0,1,
                                      0,1,1,
                                      0,0,1,
                                      0,0,1,
                                      0,0,1
                              },
                              { //2
                                      1,1,1,
                                      0,0,1,
                                      0,1,1,
                                      1,0,0,
                                      1,1,1
                              },
                              { //3
                                      1,1,1,
                                      0,0,1,
                                      1,1,1,
                                      0,0,1,
                                      1,1,1
                              },
                              { //4
                                      1,0,1,
                                      1,0,1,
                                      1,1,1,
                                      0,0,1,
                                      0,0,1
                              },
                              { //5
                                      1,1,1,
                                      1,0,0,
                                      1,1,1,
                                      0,0,1,
                                      1,1,1
                              },
                              { //6
                                      1,1,1,
                                      1,0,0,
                                      1,1,1,
                                      1,0,1,
                                      1,1,1
                              },
                              { //7
                                      1,1,1,
                                      1,0,1,
                                      0,0,1,
                                      0,0,1,
                                      0,0,1
                              },
                              { //8
                                      1,1,1,
                                      1,0,1,
                                      1,1,1,
                                      1,0,1,
                                      1,1,1
                              },
                              { //9
                                      1,1,1,
                                      1,0,1,
                                      1,1,1,
                                      0,0,1,
                                      1,1,1
                              }
                      };

int font_table2[][5*7]={
                               { //0
                                       0,1,1,1,0,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,0
                               },
                               { //1
                                       0,1,1,0,0,
                                       0,0,1,0,0,
                                       0,0,1,0,0,
                                       0,0,1,0,0,
                                       0,0,1,0,0,
                                       0,0,1,0,0,
                                       1,1,1,1,1
                               },
                               { //2
                                       0,1,1,1,0,
                                       1,0,0,0,1,
                                       0,0,0,1,0,
                                       0,0,1,0,0,
                                       0,1,0,0,0,
                                       1,0,0,0,0,
                                       1,1,1,1,1
                               },
                               { //3
                                       0,1,1,1,0,
                                       1,0,0,0,1,
                                       0,0,0,0,1,
                                       0,0,1,1,0,
                                       0,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,0
                               },
                               { //4
                                       0,0,0,1,0,
                                       0,0,1,1,0,
                                       0,1,0,1,0,
                                       1,0,0,1,0,
                                       1,1,1,1,1,
                                       0,0,0,1,0,
                                       0,0,1,1,1
                               },
                               { //5
                                       0,1,1,1,1,
                                       0,1,0,0,0,
                                       0,1,0,0,0,
                                       0,1,1,1,0,
                                       0,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,0
                               },
                               { //6
                                       0,0,1,1,1,
                                       0,1,0,0,0,
                                       1,0,0,0,0,
                                       1,1,1,1,0,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,0
                               },
                               { //7
                                       1,1,1,1,1,
                                       1,0,0,0,1,
                                       0,0,0,0,1,
                                       0,0,0,1,0,
                                       0,0,0,1,0,
                                       0,0,1,0,0,
                                       0,0,1,0,0
                               },
                               { //8
                                       0,1,1,1,0,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,0,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,0
                               },
                               { //9
                                       0,1,1,1,0,
                                       1,0,0,0,1,
                                       1,0,0,0,1,
                                       0,1,1,1,1,
                                       0,0,0,0,1,
                                       0,0,0,1,0,
                                       1,1,1,0,0
                               }
                       };

//Main drawing part
void DrawCustomFont_SingleChar (GC *_gc, int elem_index, int x1, int y1, int color)
{
	if(!big)
	{
		for (int i = (0) ; i < 15 ; i++)
		{
			if (Pixel_Visible(font_table[elem_index][i])) //checking every pixel in font_table[elem_index]
			{
				if (i < 3)
					GC_SetPixel( _gc, x1+i, y1, color );
				else if (i >= 3 && i < 6)
					GC_SetPixel( _gc, x1+i-3, y1+1, color );
				else if (i >= 6 && i < 9)
					GC_SetPixel( _gc, x1+i-6, y1+2, color );
				else if (i >= 9 && i < 12)
					GC_SetPixel( _gc, x1+i-9, y1+3, color );
				else if (i >= 12 && i < 15)
					GC_SetPixel( _gc, x1+i-12, y1+4, color );
			}
		}
	}else
	{
		for (int i = (0) ; i < 35 ; i++)
		{
			if (Pixel_Visible(font_table2[elem_index][i])) //checking every pixel in font_table[elem_index]
			{
				if (i < 5)
					GC_SetPixel( _gc, x1+i, y1, color );
				else if (i >= 5 && i < 10)
					GC_SetPixel( _gc, x1+i-5, y1+1, color );
				else if (i >= 10 && i < 15)
					GC_SetPixel( _gc, x1+i-10, y1+2, color );
				else if (i >= 15 && i < 20)
					GC_SetPixel( _gc, x1+i-15, y1+3, color );
				else if (i >= 20 && i < 25)
					GC_SetPixel( _gc, x1+i-20, y1+4, color );
				else if (i >= 25 && i < 30)
					GC_SetPixel( _gc, x1+i-25, y1+5, color );
				else if (i >= 30 && i < 35)
					GC_SetPixel( _gc, x1+i-30, y1+6, color );
			}
		}
	}
}

void DrawCustomFontText (GC *_gc, char *str, int x1, int y1, int color)
{
	int len = strlen(str);
	int x = x1;
	for (int i = len ; i >(-1) ; i--)
	{
		DrawCustomFont_SingleChar (_gc,CHAR(str[i]),x,y1,color);
		if(big) x-=6; else x-=4;
	}
}

int ShowAuthorInfo(void *mess ,BOOK* book)
{
	MSG * msg = (MSG*)mess;
	MessageBox(EMPTY_SID,STR("Cpu Widget 2.0 \n zylka \nthanks mc_kibel"), NOIMAGE, 1, 5000,msg->book);
	return(1);
}

void Send_REDRAW_RELEASE()
{
	REDRAW_RELEASE_MESSAGE *sbm = new REDRAW_RELEASE_MESSAGE;

	sbm->SB_OldOnRedraw = Display_oldReDraw;
	sbm->SB_NewOnRedraw = Display_ReDraw;

	UI_Event_wData(SBY_REDRAW_RELEASE_EVENT, sbm, (void (*)(void*))mfree_adr());
}

int SB_ELF_Killed(void *mess, BOOK *book)
{
	REDRAW_RELEASE_MESSAGE * sbm =(REDRAW_RELEASE_MESSAGE*)mess;
	REDRAW_RELEASE_MESSAGE * ms = 0;

	if (sbm->SB_NewOnRedraw == Display_oldReDraw)
	{
		if(!ms)
		{
			ms = new REDRAW_RELEASE_MESSAGE;
			memcpy(ms, sbm, sizeof(REDRAW_RELEASE_MESSAGE));
		}

		if (sbm->SB_OldOnRedraw!=EMPTY_REDRAW_METHOD) Display_oldReDraw = sbm->SB_OldOnRedraw;

		DISP_DESC_SetOnRedraw(DispObject_GetDESC(GUI_display), Display_ReDraw);

		ms->SB_OldOnRedraw = EMPTY_REDRAW_METHOD;
		ms->SB_NewOnRedraw = Display_ReDraw;
	}
	if(ms)
	{
		UI_Event_wData(SBY_REDRAW_RELEASE_EVENT ,ms,(void (*)(void*))mfree_adr());
		return(BLOCK_EVENT_GLOBALLY);
	}
	return(0);
}

int TerminateSBDraw(void * ,BOOK* book)
{
	Send_REDRAW_RELEASE();
	FreeBook(book);
	return(1);
}

void getspeed()
{
	switch(SPEED)
	{
	case 0:
		tim=4000;
		cnt=0.25;
		break;
	case 1:
		tim=2000;
		cnt=0.5;
		break;
	case 2:
		tim=1000;
		cnt=1;
		break;
	case 3:
		tim=500;
		cnt=2;
		break;
	case 4:
		tim=250;
		cnt=4;
		break;
	case 5:
		tim=125;
		cnt=8;
		break;
	case 6:
		tim=63;
		cnt=16;
		break;
	}
}


static int ReconfigElf(void *mess ,BOOK *book)
{
	RECONFIG_EVENT_DATA *reconf=(RECONFIG_EVENT_DATA *)mess;
	int result=0;
	if (wstrcmpi(reconf->path,successed_config_path)==0 && wstrcmpi(reconf->name,successed_config_name)==0)
	{
		InitConfig();
		result=1;
		getspeed();
	}
	return(result);
}

int onBcfgConfig(void *mess, BOOK *book)
{
	MSG_BCFG *msg = (MSG_BCFG *)mess;
	wchar_t *tmp = new wchar_t[256];
	wstrcpy(tmp,msg->bcfg_p);
	wstrcat(tmp,L"/");
	wstrcat(tmp,msg->bcfg_n);
	elfload(tmp,(void *)successed_config_path,(void *)successed_config_name,0);
	return(1);
}


const PAGE_MSG CpuW_PageEvents[]@ "DYN_PAGE" ={
                        SBY_REDRAW_RELEASE_EVENT  , SB_ELF_Killed,
                        ELF_RECONFIG_EVENT        , ReconfigElf,
                        ELF_BCFG_CONFIG_EVENT     , onBcfgConfig,
                        ELF_TERMINATE_EVENT       , TerminateSBDraw,
                        ELF_SHOW_INFO_EVENT       , ShowAuthorInfo,
                        NIL_EVENT_TAG             , NULL
                };

PAGE_DESC base_page ={"CPUWI_BasePage",0,CpuW_PageEvents};

void elf_exit(void)
{
	kill_data(&ELF_BEGIN, (void(*)(void*))mfree_adr());
}

struct Punkt {
	double x, y;
};
Punkt pP;
int s_angle;
int s_angle1;

struct Trojkat {
	Punkt A, B, C;
};

void rot(Punkt* pP, double phi) {
	static double conver = atan(1.)/45;
	phi = phi*conver; // stopnie -> radiany

	double c = pP->x;
	pP->x = pP->x * cos(phi) - pP->y * sin(phi);
	pP->y =     c * sin(phi) + pP->y * cos(phi);
}

void rot(Trojkat* pT, double phi) {
	rot( &pT->A, phi);
	rot( &pT->B, phi);
	rot( &pT->C, phi);
}

void hand_display(int x,int y,double angle,int len,int color)
{
	if(bol)
		if(blur)
		{
			for (int i = 1 ; i < bol+1 ; i++)
			{

				Punkt A;
				A.x = 0;
				A.y =  len_s;
				Punkt B = { i, 0 };
				Punkt C = { -(i) };
				C.y = 0;
				Trojkat T = { A, B };
				T.C = C;
				rot(&T,s_angle);

				GVI_GC gvigc = NULL;
				CANVAS_Get_GviGC(context->pcanvas, &gvigc);

				POINT p[3];
				p[0].x = T.A.x+x;
				p[0].y = T.A.y+y;
				p[1].x = T.B.x+x;
				p[1].y = T.B.y+y;
				p[2].x = T.C.x+x;
				p[2].y = T.C.y+y;

				GVI_BRUSH brush = GVI_CreateSolidBrush(color);
				GVI_FillPolygon(gvigc, p, 3, brush);
				GVI_Delete_GVI_Object(&brush);
			}
		} else
		{
			Punkt A;
			A.x = 0;
			A.y =  len_s;
			Punkt B = { bol, 0 };
			Punkt C = { -(bol) };
			C.y = 0;
			Trojkat T = { A, B };
			T.C = C;
			rot(&T,s_angle);

			GVI_GC gvigc = NULL;
			CANVAS_Get_GviGC(context->pcanvas, &gvigc);

			POINT p[3];
			p[0].x = T.A.x+x;
			p[0].y = T.A.y+y;
			p[1].x = T.B.x+x;
			p[1].y = T.B.y+y;
			p[2].x = T.C.x+x;
			p[2].y = T.C.y+y;

			GVI_BRUSH brush = GVI_CreateSolidBrush(color);
			GVI_FillPolygon(gvigc, p, 3, brush);
			GVI_Delete_GVI_Object(&brush);
		}
}

void hand_display1(int x,int y,double angle,int len,int color)
{

	if(bolr)
		if(blur)
		{
			for (int i = 1 ; i < bolr+1 ; i++)
			{

				Punkt A;
				A.x = 0;
				A.y =  len_sr;
				Punkt B = { i, 0 };
				Punkt C = { -(i) };
				C.y = 0;
				Trojkat T = { A, B };
				T.C = C;
				rot(&T,s_angle1);

				GVI_GC gvigc = NULL;
				CANVAS_Get_GviGC(context->pcanvas, &gvigc);

				POINT p[3];
				p[0].x = T.A.x+x;
				p[0].y = T.A.y+y;
				p[1].x = T.B.x+x;
				p[1].y = T.B.y+y;
				p[2].x = T.C.x+x;
				p[2].y = T.C.y+y;

				GVI_BRUSH brush = GVI_CreateSolidBrush(color);
				GVI_FillPolygon(gvigc, p, 3, brush);
				GVI_Delete_GVI_Object(&brush);
			}
		} else
		{
			Punkt A;
			A.x = 0;
			A.y =  len_sr;
			Punkt B = { bolr, 0 };
			Punkt C = { -(bolr) };
			C.y = 0;
			Trojkat T = { A, B };
			T.C = C;
			rot(&T,s_angle1);

			GVI_GC gvigc = NULL;
			CANVAS_Get_GviGC(context->pcanvas, &gvigc);

			POINT p[3];
			p[0].x = T.A.x+x;
			p[0].y = T.A.y+y;
			p[1].x = T.B.x+x;
			p[1].y = T.B.y+y;
			p[2].x = T.C.x+x;
			p[2].y = T.C.y+y;

			GVI_BRUSH brush = GVI_CreateSolidBrush(color);
			GVI_FillPolygon(gvigc, p, 3, brush);
			GVI_Delete_GVI_Object(&brush);
		}
}

inline double ToRadians( double theta )
{
	return (theta*PI)/180.0;
}



void onfTimer (u16 tmr , void *)
{
	cpu=100-(count/2.5);//-100;

	count=0;
	DispObject_InvalidateRect(GUI_display,0);
	Timer_ReSet(&ftimer,tim,onfTimer,0);
}

void draw()
{
	int heap=GetFreeBytesOnHeap()/1024;
	char tmp[4] = {0,};char tmp1[4] = {0,};
	sprintf (tmp,"%d",cpu);
	DrawCustomFontText (context, tmp, X1-kor_x, Y1+kor_y, color_n);
	sprintf (tmp1,"%d",(heap/maxr));
	DrawCustomFontText (context, tmp1, X1+korr_x, Y1-korr_y, color_n);
	s_angle = (cpu* 2.5)+55;//
	s_angle1 = ((heap/maxr)*2.5)+55;
	hand_display(X1-kor_cx,Y1+kor_cy,ToRadians( s_angle),len_s,color_s);
	hand_display1(X1+kor_rx,Y1-kor_ry,ToRadians( s_angle1),len_s,color_s);
}

void Display_ReDraw(DISP_OBJ * DO,int a, int b,int c)
{
	if(image.ImageID!=0xFFFF) GC_PutChar(context,X1-imgw/2,Y1-imgh/2,0,0,image.ImageID);
	draw();
	if(image1.ImageID!=0xFFFF) GC_PutChar(context,X1-kor_cox,Y1-kor_coy,0,0,image1.ImageID);
	if(image2.ImageID!=0xFFFF) GC_PutChar(context,X1+kor_rox,Y1-kor_roy,0,0,image2.ImageID);
	if(Display_oldReDraw) Display_oldReDraw(DO,a,b,c);
}

wchar_t RegisterImage(IMG * i , wchar_t * path, wchar_t * fname)
{
	char error_code;
	i->ImageID=0xFFFF;
	i->ImageHandle=0xFFFF;
	if (!fstat(path,fname,0))
	{
		if (!REQUEST_IMAGEHANDLER_INTERNAL_GETHANDLE(SYNC,&i->ImageHandle,&error_code))
		{
			if (!REQUEST_IMAGEHANDLER_INTERNAL_REGISTER(SYNC,i->ImageHandle,path,fname,0,&i->ImageID,&error_code))
			{
				if (error_code)
				{
					i->ImageHandle=0xFFFF;
				}
			}
		}
	}
	return 0;
}


void onCloseMyBook(BOOK * book)
{
	if (book)
	{
		char error;
		stop(pid);
		Timer_Kill(&ftimer);
		if(Display_desc) DISP_DESC_SetOnRedraw(Display_desc, Display_oldReDraw);
		if(image.ImageID) REQUEST_IMAGEHANDLER_INTERNAL_UNREGISTER(SYNC,image.ImageHandle,0,0,image.ImageID,1,&error);
		if(image1.ImageID) REQUEST_IMAGEHANDLER_INTERNAL_UNREGISTER(SYNC,image1.ImageHandle,0,0,image1.ImageID,1,&error);
		if(image2.ImageID) REQUEST_IMAGEHANDLER_INTERNAL_UNREGISTER(SYNC,image2.ImageHandle,0,0,image2.ImageID,1,&error);
		SUBPROC(elf_exit);
	}
}

BOOK * CreateSBDBook()
{
	BOOK * SBDBook= new BOOK;
	CreateBook(SBDBook,onCloseMyBook,&base_page,"CpuWidget",-1,0);
	return(SBDBook);
}


OS_PROCESS(my_proc)
{
	while(true)
	{
		count+=cnt;
		delay(1);
	}
}


int main (void)
{
	Height=Display_GetHeight(0);
	Width=Display_GetWidth(0);;
	CreateSBDBook();
	InitConfig();

	if(!GUI_display)
	{
		GUI_display = GUIObject_GetDispObject( SBY_GetStatusIndication(Find_StandbyBook()) );
		Display_oldReDraw = DispObject_GetOnRedraw(GUI_display);
		Display_desc = DispObject_GetDESC (GUI_display);
		DISP_DESC_SetOnRedraw(Display_desc, Display_ReDraw);
	}

	wchar_t myFolder[512];
	wstrcpy(myFolder,GetDir(MEM_INTERNAL+DIR_ELFS_CONFIG));
	wstrcat(myFolder,L"/widgets/");
	RegisterImage(&image,myFolder,L"back_lrg.png");
	RegisterImage(&image1,myFolder,L"proc_lrg.png");
	RegisterImage(&image2,myFolder,L"ram_lrg.png");
	imgh=GetImageHeight(image.ImageID);
	imgw=GetImageWidth(image.ImageID);
	context = get_DisplayGC();
	getspeed();

	pid=create_process(0,"cpuwidget",my_proc,1024,(OSPRIORITY)31 ,0,0,0,0,0);
	start(pid);
	MMIPROC((void (*)(void))onfTimer);
	return(0);
}


